let Vue = null;
class Store {
  constructor(options){
    // options  {states  mutations ...}
    let vm = new Vue({
      data:{
        state:options.state
      }
    })
    // this.state = options.state  //这么写不存在响应式
    this.state = vm.state ;// 这样写可以保证数据 被劫持

    this.mutations = {};// 这里存储的是用来更改state的方法
    let mutations = options.mutations || {};
    Object.keys(mutations).forEach(key=>{
      this.mutations[key] = (aaa) => {
        mutations[key].call(this,this.state,aaa)
      }
    })
    // 以上7行代码能够保证 当 mutatiosn中的方法执行的时候 
    // 里边的this是store实例，会有一个默认参数 state

    this.actions = Object.create(null);
    let actions = options.actions || {};
    Object.keys(actions).forEach(key=>{
      this.actions[key] = (aaa)=>{
        actions[key].call(this,this,aaa)
      }
    })

    this.getters = {};
    let getters = options.getters || {};
    Object.keys(getters).forEach(key=>{
      Object.defineProperty(this.getters,key,{
        get: ()=>{
          return getters[key].call(this,this.state)
        }
      })
    })




    this.commit = (type,option)=>{
      // this.commit(type,option)
      this.mutations[type](option)
    }
  }
  // commit(type,option){
  //   this.mutations[type](option)
  // }
  dispatch(type,option){
    this.actions[type](option)
  }
}


function install(_vue){
  // 在 Vue.use的时候 会默认执行这个方法 并把 Vue类传进来
  Vue = _vue;
  //一旦把store实例注入到跟实例上 那么每一个组件上都可以调用到 $store
  // 这里时借助了 混入  mixin
  // 全局混入  是把当前的配置对象合并到每一个组件中
  // 局部混入 mixins 是只当前的配置对象合并到这个组件中  
  Vue.mixin({
    // 会把当前对象混入到每一个 实例中  混入的钩子函数是先执行的；  若属性名或者方法名重复的时候  以组件的为基准
    beforeCreate() {
      // 每一个组件 都会执行这个钩子函数
      if(this.$options.store){
        //$options 里边有 我们在 new VUE时 传递的参数
        // 若 $options 中有 store这个属性 证明 当前的这个this时 new 出来的跟实例
        this.$store = this.$options.store;
      }else if(this.$parent){
        // 证明当前 this 组件 是 根实例的子组件
        this.$store = this.$parent.$store
      }
    },
  })
  console.log('install',_vue)
}

function mapState(ary=[]){
  let obj ={};
  ary.forEach(key=>{
    obj[key] = function (){
      // this 是vuex实例 还是 组件 ？？
      // this 是当前组件
      return this.$store.state[key]
    }
  })
  return obj; //{count:function(){return this.$store.state[key]}}
}
function mapGetters(ary=[]){
  let obj ={};
  ary.forEach(key=>{
    obj[key] = function (){
      // this 是vuex实例 还是 组件 ？？
      // this 是当前组件
      return this.$store.getters[key]
    }
  })
  return obj; 
}
function mapMutations(ary=[]){
  let obj ={};
  ary.forEach(key=>{
    obj[key] = function(params){
      return this.$store.commit(key,params)
    }
  })
  return obj; 
}
function mapActions(ary=[]){
  let obj ={};
  ary.forEach(key=>{
    obj[key] = function(params){
      return this.$store.dispatch(key,params)
    }
  })
  return obj; 
}
export default{
  Store,
  install,
  mapState: mapState,
  mapMutations: mapMutations,
  mapGetters: mapGetters,
  mapActions: mapActions,
}